//
//  ARWorkDetailViewModel.swift
//  AquaRaft
//
//  Created by 何启亮 on 2024/4/14.
//

import Foundation
import AVFoundation
import JKSwiftExtension

/// 音频播放相关操作
protocol ARWorkDetailViewModelAudioOperationDelegate: NSObjectProtocol {
    
    /// 刷新UI
    func viewModel(_ viewModel: ARWorkDetailViewModel, shouldRefreshUI cellDatas: [ARWorkCommentCellData])
    
    /// 播放失败
    func viewModel(_ viewModel: ARWorkDetailViewModel, playAudioError error: Error?)
    
}

/// 作品详情页ViewModel
/// - note:
///  主要功能:
///     1. 拉取作品信息
///     2. 作品点赞
///     3. comment点赞
///     4. 发表comment(text / audio)
class ARWorkDetailViewModel: NSObject {
    
    // MARK: - Proprety
    
    /// 作品id
    let workId: String
    let style: ARWorkDetailPathStyle
    
    /// 评论
    private var _comments: [ARWorkCommentCellData] = []
    var comment: [ARWorkCommentCellData] {
        _comments
    }
    
    private var _workModel: ARWorkModel?
    var workModel: ARWorkModel? {
        _workModel
    }
    
    /// 当前正在播放的celldata
    private var playingCommentCellData: ARWorkCommentCellData?
    private var audioPlayer: AVAudioPlayer?
    private var audioObserverTimer: JKWeakTimer?
    
    weak var audioDelegate: ARWorkDetailViewModelAudioOperationDelegate?
    
    // MARK: - Init
    
    init(workId: String, style: ARWorkDetailPathStyle) {
        self.workId = workId
        self.style = style
    }
    
    // MARK: - Action
    
    /// 获取数据
    func fetchWork(_ completion: @escaping (_ err: Error?) -> Void) {
        
        ARHelper.afterAsyncInMainQueue { [weak self] in
            guard let self = self else {
                return
            }
            
            let work: ARWorkModel?
            if self.style == .discover {
                work = ARDataCenter.default.fetchWork(workId)
            } else {
                // 主页
                work = ARDataCenter.default.fetchRecommendation(workId)
            }
            _workModel = work
            _comments.removeAll()
            
            guard let work = work else {
                completion(ARDataCenterError.unknown)
                return
            }
            
            // config comment
            if let comments = work.comments {
                for comment in comments {
                    let celldata = ARWorkCommentCellData(commentModel: comment, style: style)
                    _comments.append(celldata)
                }
            }
            completion(nil)
        }
    }
    
    /// 点赞、取消点赞作品
    func likeOrUnLikeWork(_ completion: @escaping (_ err: Error?) -> Void) {
        
        guard let work = workModel else {
            completion(ARDataCenterError.permissionDenied)
            return
        }
        
        let likeOrUnlike = !(work.isLike ?? false)
        ARHelper.afterAsyncInMainQueue { [weak self] in
            guard let self = self else {
                return
            }
            
            let callback: (ARDataCenterError?) -> Void = { err in
                if err == nil {
                    work.isLike = likeOrUnlike
                }
                completion(err)
            }
            
            if self.style == .discover {
                ARDataCenter.default.likeOrUnlikeWork(self.workId, like: likeOrUnlike, completion: callback)
            } else {
                ARDataCenter.default.likeOrUnlikeRecommendation(self.workId, like: likeOrUnlike, completion: callback)
            }
        }
    }
    
    // 发表comment
    
    func postTextComment(_ textComment: String, completion: @escaping (_ err: Error?) -> Void) {
        ARHelper.afterAsyncInMainQueue { [weak self] in
            guard let self = self else {
                return
            }
            
            let callback: (ARCommentModel?, ARDataCenterError?) -> Void = { [weak self] commentModel, err in
                guard let self = self else {
                    return
                }
                if let err = err {
                    completion(err)
                    return
                }
                
                // 成功
                if let commentModel = commentModel {
                    _comments.append(ARWorkCommentCellData.init(commentModel: commentModel, style: style))
                }
                completion(nil)
            }
            
            if self.style == .discover {
                ARDataCenter.default.postTextComment(textComment, workId: workId, completion: callback)
            } else {
                ARDataCenter.default.postRecommendationTextComment(textComment, workId: workId, completion: callback)
            }
        }
    }
    
    func postAudioComment(_ audioPath: String, duration: TimeInterval, completion: @escaping (_ err: Error?) -> Void) {
        ARHelper.afterAsyncInMainQueue { [weak self] in
            guard let self = self else {
                return
            }
            ARDataCenter.default.postAudioComment(audioPath, duration: duration, workId: workId) { [weak self] commentModel, err in
                guard let self = self else {
                    return
                }
                if let err = err {
                    completion(err)
                    return
                }
                
                // 成功
                if let commentModel = commentModel {
                    _comments.append(ARWorkCommentCellData.init(commentModel: commentModel, style: style))
                }
                completion(nil)
            }
        }
    }

    func likeOrUnLikeComment(_ commentId: String, like: Bool, completion: @escaping (_ err: Error?) -> Void) {
        ARHelper.afterAsyncInMainQueue { [weak self] in
            guard let self = self else {
                return
            }
            if self.style == .discover {
                ARDataCenter.default.likeOrUnlikeComment(workId, commentId: commentId, like: like) { err in
                    completion(err)
                }
            } else {
                ARDataCenter.default.likeOrUnlikeRecommendationComment(workId, commentId: commentId, like: like) { err in
                    completion(err)
                }
            }
            
        }
    }
    
    /// 关注
    func followUser(_ userId: String, completion: @escaping (Error?) -> Void) {
        // 因为 datacenter 获取的数据都是对象，所以在datacenter中修改之后，其他地方也会是最新的数据
        ARDataCenter.default.followOrUnfollowUser(userId, followOrUnfollow: true) { err in
            completion(err)
        }
    }
    
}

/// 播放相关
extension ARWorkDetailViewModel: AVAudioPlayerDelegate {
    
    // MARK: - Audio play
    
    /// 暂停或播放语音
    func playOrStopAudio(_ commentCellData: ARWorkCommentCellData) {
        guard let audioPath = commentCellData.commentModel.audioPath else {
            return
        }
        
        var refreshCellDatas: [ARWorkCommentCellData] = []
        // 判断是否一致
        if let playingCommentCellData = self.playingCommentCellData {
            // 有值
            self._stopCurrentPlayer()
            
            refreshCellDatas.append(playingCommentCellData)
            if playingCommentCellData == commentCellData {
                // 回调
                self.audioDelegate?.viewModel(self, shouldRefreshUI: refreshCellDatas)
                return
            }
        }
        
        // 播放当前celldata
        
        do {
            
            try AVAudioSession.sharedInstance().setCategory(.playback)
            try AVAudioSession.sharedInstance().setActive(true)
            
            let player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath))
            player.delegate = self
            player.prepareToPlay()
            if !player.play() {
                // 回调失败
                self.audioDelegate?.viewModel(self, playAudioError: (NSError(domain: "AR.AudioPlay", code: -100, userInfo: [NSLocalizedDescriptionKey: "Failed to play audio"])))
            } else {
                self.playingCommentCellData = commentCellData
                commentCellData.playing = true

                self.startTimerObserver()
                refreshCellDatas.append(commentCellData)
                self.audioPlayer = player
            }
        } catch {
            // 回调失败
            self.audioDelegate?.viewModel(self, playAudioError: error)
        }
        
        // 刷新
        self.audioDelegate?.viewModel(self, shouldRefreshUI: refreshCellDatas)
    }
    
    /// 停止当前播放
    private func _stopCurrentPlayer() {
        if let playingCommentCellData = self.playingCommentCellData {
            // 有值
            audioPlayer?.stop()
            playingCommentCellData.playing = false
            
            self.stopTimerObserver()
            self.playingCommentCellData = nil
            self.audioPlayer = nil
        }
    }
    
    func stopCurrentPlayer() {
        if let playingCommentCellData = self.playingCommentCellData {
            self._stopCurrentPlayer()
            
            self.audioDelegate?.viewModel(self, shouldRefreshUI: [playingCommentCellData])
        }
    }
    
    
    // MARK: - Delegate
    
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        
       // 直接干掉current就OK，先不判断是否同一个
        self.stopCurrentPlayer()
    }

    func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) {
        // 直接干掉current就OK，先不判断是否同一个
        self.stopCurrentPlayer()
        
        self.audioDelegate?.viewModel(self, playAudioError: error)
    }
    
    // MARK: - Timer
    
    private func startTimerObserver() {
        // 先stop
        self.stopTimerObserver()
        
        guard let _ = self.playingCommentCellData else {
            return
        }
        
        self.audioObserverTimer = JKWeakTimer.init(timeInterval: 0.1, target: self, selector: #selector(timerCallback), repeats: true)
        self.audioObserverTimer?.fire()
    }
    
    private func stopTimerObserver() {
        if let audioObserverTimer = self.audioObserverTimer {
            audioObserverTimer.invalidate()
            self.audioObserverTimer = nil
        }
    }
    
    @objc func timerCallback() {
        guard let playingCommentCellData = self.playingCommentCellData,
              let audioPlayer = self.audioPlayer else {
            self.stopTimerObserver()
            return
        }
        
        // 回调
        playingCommentCellData.countDown = playingCommentCellData.duration - audioPlayer.currentTime
        self.audioDelegate?.viewModel(self, shouldRefreshUI: [playingCommentCellData])
    }
}
